﻿// ———————————————————————–
// <copyright file="History.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// History.cs - "Put and Get information from the EDXL History database."
// Project: "EDXLSharp_Router"- "EDXLHistory"
//
// Language:    C#, .NET 4.0
// Platform:    Windows 7, VS 2012
// Author:      Brian Wilkins The MITRE Corporation
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using CoT_Library;
using CoT_Library.Details;
using EDXLCoT;
using EDXLSharp;
using EDXLSharp.CAPLib;
using EDXLSharp.EDXLDELib;
using EDXLSharp.EDXLHAVE_2_0Lib;
using GeoOASISWhereLib;
using GISUtil;
using ICNETDAL;
using ICNETServices;
using MEXLSitRepLib;

namespace EDXLHistory
{
  /// <summary>
  /// Contains methods for recording and retreiving EDXL DE messages.
  /// </summary>
  public class History
  {
    /// <summary>
    /// The path to the database.
    /// </summary>
    private static string databaseConnectionString = "Data Source=localhost;Initial Catalog=" + "EDXLHistory" + ";Integrated Security=True";

    /// <summary>
    /// A code that corresponds to the status of the service.
    /// </summary>
    public enum ServiceStatusEnum
    {
      /// <summary>
      /// The service completed successfully.
      /// </summary>
      Success = 1,

      /// <summary>
      /// The service encountered an error.
      /// </summary>
      Error,

      /// <summary>
      /// The service started work.
      /// </summary>
      Started,
    }

    #region Public Methods

    /// <summary>
    /// Adds an empty entry to the database.
    /// </summary>
    /// <returns>The ID associated with the event logged.</returns>
    public static int AddLoggingEventToDB()
    {
      return AddReceivedMessageToDB("0.0.0.0", "none", new XElement("NoContent"));
    }

    /// <summary>
    /// Adds a received DE message to the database 
    /// </summary>
    /// <param name="deID">Distribution Id</param>
    /// <param name="deSender">Sender Id</param>
    /// <param name="deSent">DE DateTimeSent</param>
    /// <param name="senderIP">Sender'serializer IP address</param>
    /// <param name="senderURI">Sender'serializer URL</param>
    /// <param name="xml">Raw DE XML</param>
    /// <returns></returns>
    public static int AddReceivedMessageToDB(string deID, string deSender, DateTime deSent, string senderIP, string senderURI, XElement xml)
    {
      Received newIncomingMsg = new Received();
      newIncomingMsg.DEId = deID;
      newIncomingMsg.DESender = deSender;
      newIncomingMsg.DEDateTimeSent = deSent;
      newIncomingMsg.SenderIP = senderIP;
      newIncomingMsg.SenderURI = senderURI;

      Message newMsg = new Message();
      newMsg.Body = xml;

      newIncomingMsg.Messages.Add(newMsg);

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      linqDB.Receiveds.InsertOnSubmit(newIncomingMsg);
      Submit(linqDB);

      return newIncomingMsg.Id;
    }

    /// <summary>
    /// Logs an event to the database.
    /// </summary>
    /// <param name="xml">The item to be logged, in XML format. </param>
    /// <returns>The ID associated with the event logged.</returns>
    public static int AddReceivedMessageToDB(string senderIP, string senderURI, XElement xml)
    {
      return AddReceivedMessageToDB("", "", DateTime.Now, senderIP, senderURI, xml);
    }

    public static void AddServiceStatusToDB(string deId, string deSender, DateTime deSent, string serviceName, ServiceStatusEnum serviceStatus, DateTime serviceTime, string serviceMessage)
    {
      int receivedId;

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);

      try
      {
        receivedId = (from p in linqDB.Receiveds
              where p.DEId == deId && p.DESender == deSender && p.DEDateTimeSent == deSent
              select p.Id).FirstOrDefault();
      }
      catch (InvalidOperationException)
      {
        return;
      }

      ServiceStatus serviceEntry = new ServiceStatus();
      serviceEntry.ReceivedId = receivedId;
      serviceEntry.ServiceName = serviceName;
      serviceEntry.StatusMessage = serviceMessage;
      serviceEntry.StatusTime = serviceTime;
      serviceEntry.ServiceStatusValue = serviceStatus.ToString();

      linqDB.ServiceStatus.InsertOnSubmit(serviceEntry);
      Submit(linqDB);
    }

    /// <summary>
    /// Gets information about the 2nd frame on the stack so that it can be logged to the database.
    /// </summary>
    /// <returns>A string which contains the method name, line number, and file name of the 2nd frame on the stack. </returns>
    private static string GetStackLocationForWriteCaller()
    {
      StackTrace stackTrace = new StackTrace(true);
      StackFrame frame = stackTrace.GetFrame(2);

      return frame.GetMethod().Name + "  line " + frame.GetFileLineNumber() + " in" + frame.GetFileName();
    }

    /// <summary>
    /// Get all entries in the Received table
    /// </summary>
    /// <returns>XML representing entries in the Received table</returns>
    public static List<XElement> GetReceivedAll()
    {
      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);

      return CreateReceivedList(linqDB.Receiveds.ToList());
    }

    /// <summary>
    /// Get all entries in the Received table based on the supplied DE parameters
    /// </summary>
    /// <param name="deID">Id of the DE to retrieve</param>
    /// <param name="deSender">Sender of the DE to retrieve</param>
    /// <param name="deDateTimeSent">DateTimeSent of the DE to retrieve</param>
    /// <returns>XML representing the matching entries in the Received table</returns>
    public static List<XElement> GetReceivedByDE(string deID, string deSender, string deDateTimeSent)
    {
      List<Received> recvdList = null;

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      DateTime sentDT;

      //if the supplied DateTimeSent is a valid DateTime
      if (DateTime.TryParse(deDateTimeSent, out sentDT))
      {
        //match on DE Id, DE sender, and DE datetimesent
        if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from p in linqDB.Receiveds
                        where p.DEId == deID && p.DESender == deSender && p.DEDateTimeSent == sentDT
                        select p;

          recvdList = varData.ToList<Received>();
        }
        //match on DE Id and DE datetimesent
        else if (!string.IsNullOrWhiteSpace(deID))
        {
          var varData = from p in linqDB.Receiveds
                        where p.DEId == deID && p.DEDateTimeSent == sentDT
                        select p;

          recvdList = varData.ToList<Received>();
        }
        //match on DE sender and DE datetimesent
        else if (!string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from p in linqDB.Receiveds
                        where p.DESender == deSender && p.DEDateTimeSent == sentDT
                        select p;

          recvdList = varData.ToList<Received>();
        }
        //match on DE datetimesent
        else
        {
          var varData = from p in linqDB.Receiveds
                        where p.DEDateTimeSent == sentDT
                        select p;

          recvdList = varData.ToList<Received>();
        }
          
      }
      else
      {
        //match on DE Id and DE sender
        if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from p in linqDB.Receiveds
                        where p.DEId == deID && p.DESender == deSender 
                        select p;

          recvdList = varData.ToList<Received>();
        }
        //match on DE Id
        else if (!string.IsNullOrWhiteSpace(deID))
        {
          var varData = from p in linqDB.Receiveds
                        where p.DEId == deID 
                        select p;

          recvdList = varData.ToList<Received>();
        }
        //match on DE sender
        else if (!string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from p in linqDB.Receiveds
                        where p.DESender == deSender
                        select p;

          recvdList = varData.ToList<Received>();
        }
        //retrieve everything
        else
        {
          var varData = from p in linqDB.Receiveds
                        select p;

          recvdList = varData.ToList<Received>();
        }
          
      }

      return CreateReceivedList(recvdList);
    }

    /// <summary>
    /// Get all entries in the Received table based on the supplied time parameters
    /// </summary>
    /// <param name="startTime">Start time to match on</param>
    /// <param name="endTime">End time to match on</param>
    /// <returns>XML representing the matching entries in the Received table</returns>
    public static List<XElement> GetReceivedByTime(string startTime, string endTime)
    {
      List<Received> recvdList;

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      DateTime startDT;
      DateTime endDT;

      bool bStartTime = DateTime.TryParse(startTime, out startDT);
      bool bEndTime = DateTime.TryParse(endTime, out endDT);

      //match on start time and end time
      if (bStartTime && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEDateTimeSent >= startDT && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on start time
      else if (bStartTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEDateTimeSent >= startDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on end time
      else if (bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on everything
      else
      {
        var varData = from p in linqDB.Receiveds
                      select p;

        recvdList = varData.ToList<Received>();
      }

      return CreateReceivedList(recvdList);
    }

    /// <summary>
    /// Get all entries in the Received table based on the supplied time parameters
    /// </summary>
    /// <param name="deID">DE distribution Id to match on</param>
    /// <param name="deSender">DE sender Id to match on</param>
    /// <param name="startTime">Start time to match on</param>
    /// <param name="endTime">End time to match on</param>
    /// <returns>XML representing the matching entries in the Received table</returns>
    public static List<XElement> GetReceivedByDEAndTime(string deID, string deSender, string startTime, string endTime)
    {
      List<Received> recvdList;

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      DateTime startDT;
      DateTime endDT;

      bool bStartTime = DateTime.TryParse(startTime, out startDT);
      bool bEndTime = DateTime.TryParse(endTime, out endDT);

      //match on DE Id, DE Sender, start time and end time
      if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender) && bStartTime && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEId == deID && p.DESender == deSender && p.DEDateTimeSent >= startDT && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Id, start time and end time
      else if (!string.IsNullOrWhiteSpace(deID) && bStartTime && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEId == deID && p.DEDateTimeSent >= startDT && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Sender, start time and end time
      else if (!string.IsNullOrWhiteSpace(deSender) && bStartTime && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DESender == deSender && p.DEDateTimeSent >= startDT && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on start time and end time
      else if (bStartTime && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEDateTimeSent >= startDT && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Id, DE Sender, and start time
      else if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender) && bStartTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEId == deID && p.DESender == deSender && p.DEDateTimeSent >= startDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Id and start time
      else if (!string.IsNullOrWhiteSpace(deID) && bStartTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEId == deID && p.DEDateTimeSent >= startDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Sender and start time
      else if (!string.IsNullOrWhiteSpace(deSender) && bStartTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DESender == deSender && p.DEDateTimeSent >= startDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on start time
      else if (bStartTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEDateTimeSent >= startDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Id, DE Sender and end time
      else if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender) && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEId == deID && p.DESender == deSender && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Id and end time
      else if (!string.IsNullOrWhiteSpace(deID) && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEId == deID && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on DE Sender and end time
      else if (!string.IsNullOrWhiteSpace(deSender) && bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DESender == deSender && p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on end time
      else if (bEndTime)
      {
        var varData = from p in linqDB.Receiveds
                      where p.DEDateTimeSent <= endDT
                      select p;

        recvdList = varData.ToList<Received>();
      }
      //match on everything
      else
      {
        var varData = from p in linqDB.Receiveds
                      select p;

        recvdList = varData.ToList<Received>();
      }

      return CreateReceivedList(recvdList);
    }

    /// <summary>
    /// Get all DEs in the Message table
    /// </summary>
    /// <returns>XML representing all the DE in the Message table</returns>
    public static List<XElement> GetAllDE()
    {
      List<XElement> mylist = new List<XElement>();

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);

      foreach (Received recvd in linqDB.Receiveds)
      {
        foreach (Message msg in recvd.Messages)
        {
          mylist.Add(msg.Body);
        }
      }

      return mylist;
    }

    /// <summary>
    /// Get all DEs in the Message table based on the supplied DE parameters
    /// </summary>
    /// <param name="deID">Id of the DE to retrieve</param>
    /// <param name="deSender">Sender of the DE to retrieve</param>
    /// <param name="deDateTimeSent">DateTimeSent of the DE to retrieve</param>
    /// <returns>XML representing the matching DE in the Message table</returns>
    public static List<XElement> GetDE(string deID, string deSender, string deDateTimeSent)
    {
      List<XElement> mylist = new List<XElement>();

      DateTime sentDT;
      List<Message> msgList = null;

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);

      if (DateTime.TryParse(deDateTimeSent, out sentDT))
      {
        //match on DE Id, DE sender, and DE datetimesent
        if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DEId == deID && recv.DESender == deSender && recv.DEDateTimeSent == sentDT
                        select msg;

          msgList = varData.ToList<Message>();
        }
        //match on DE Id and DE datetimesent
        else if (!string.IsNullOrWhiteSpace(deID))
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DEId == deID && recv.DEDateTimeSent == sentDT
                        select msg;

          msgList = varData.ToList<Message>();
        }
        //match on DE sender and DE datetimesent
        else if (!string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DESender == deSender && recv.DEDateTimeSent == sentDT
                        select msg;

          msgList = varData.ToList<Message>();
        }
        //match on DE datetimesent
        else
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DEDateTimeSent == sentDT
                        select msg;

          msgList = varData.ToList<Message>();
        }
      }
      else
      {
        //match on DE Id and DE sender
        if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DEId == deID && recv.DESender == deSender
                        select msg;

          msgList = varData.ToList<Message>();
        }
        //match on DE Id
        else if (!string.IsNullOrWhiteSpace(deID))
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DEId == deID
                        select msg;

          msgList = varData.ToList<Message>();
        }
        //match on DE sender
        else if (!string.IsNullOrWhiteSpace(deSender))
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        where recv.DESender == deSender
                        select msg;

          msgList = varData.ToList<Message>();
        }
        //match on everything
        else
        {
          var varData = from msg in linqDB.Messages
                        join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                        select msg;

          msgList = varData.ToList<Message>();
        }
      }

      foreach (Message recvd in msgList)
      {
        mylist.Add(recvd.Body);
      }

      return mylist;
    }

    /// <summary>
    /// Get all DEs in the Message table based on the supplied time parameters
    /// </summary>
    /// <param name="startTime">Start time to match on</param>
    /// <param name="endTime">End time to match on</param>
    /// <returns>XML representing the matching DE in the Message table</returns>
    public static List<XElement> GetDEByTime(string startTime, string endTime)
    {
      List<XElement> mylist = new List<XElement>();
      List<Message> msgList;

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      DateTime startDT;
      DateTime endDT;

      bool bStartTime = DateTime.TryParse(startTime, out startDT);
      bool bEndTime = DateTime.TryParse(endTime, out endDT);

      //match on start time and end time
      if (bStartTime && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent >= startDT && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on start time
      else if (bStartTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent >= startDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on end time
      else if (bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on everything
      else
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      select msg;

        msgList = varData.ToList<Message>();
      }

      foreach (Message recvd in msgList)
      {
        mylist.Add(recvd.Body);
      }

      return mylist;
    }

    /// <summary>
    /// Get all DE messages in the Message table based on the supplied time parameters
    /// </summary>
    /// <param name="unitType">Unit Type to match on</param>
    /// <param name="startTime">Start time to match on</param>
    /// <param name="endTime">End time to match on</param>
    /// <returns>XML representing the matching DE messages in the Message table</returns>
    public static List<XElement> GetDEByUnitTypeAndTime(string unitType, string startTime, string endTime)
    {
      List<Message> msgList;
      List<XElement> mylist = new List<XElement>();

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      DateTime startDT;
      DateTime endDT;

      bool bStartTime = DateTime.TryParse(startTime, out startDT);
      bool bEndTime = DateTime.TryParse(endTime, out endDT);

      //match on start time and end time
      if (bStartTime && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent >= startDT && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on start time
      else if (bStartTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent >= startDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on end time
      else if (bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on everything
      else
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      select msg;

        msgList = varData.ToList<Message>();
      }

      if (!string.IsNullOrWhiteSpace(unitType))
      {
        foreach (Message recvd in msgList)
        {
          XElement xBody = recvd.Body;

          XNamespace ns = "urn:cot:mitre:org";
          XElement xCoT = xBody.Descendants(ns + "event").FirstOrDefault();

          if (xCoT != null)
          {
            XAttribute typeAttr = xCoT.Attribute("type");

            if (typeAttr != null && typeAttr.Value.Equals(unitType, StringComparison.InvariantCultureIgnoreCase))
            {
              mylist.Add(xBody);
            }
          }
        }
      }
      else
      {
        foreach (Message recvd in msgList)
        {
          mylist.Add(recvd.Body);
        }
      }

      return mylist;
    }

    /// <summary>
    /// Get all DE messages in the Message table based on the supplied time parameters
    /// </summary>
    /// <param name="deID">DE distribution Id to match on</param>
    /// <param name="deSender">DE sender Id to match on</param>
    /// <param name="startTime">Start time to match on</param>
    /// <param name="endTime">End time to match on</param>
    /// <returns>XML representing the matching DE messages in the Message table</returns>
    public static List<XElement> GetDEByDEAndTime(string deID, string deSender, string startTime, string endTime)
    {
      List<Message> msgList;
      List<XElement> mylist = new List<XElement>();

      EDXLHistoryDALDataContext linqDB = new EDXLHistoryDALDataContext(History.databaseConnectionString);
      linqDB.CommandTimeout = 60;
      DateTime startDT;
      DateTime endDT;

      bool bStartTime = DateTime.TryParse(startTime, out startDT);
      bool bEndTime = DateTime.TryParse(endTime, out endDT);

      //match on DE Id, DE Sender, start time and end time
      if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender) && bStartTime && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DESender == deSender && recv.DEDateTimeSent >= startDT && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id, start time and end time
      else if (!string.IsNullOrWhiteSpace(deID) && bStartTime && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DEDateTimeSent >= startDT && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Sender, start time and end time
      else if (!string.IsNullOrWhiteSpace(deSender) && bStartTime && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DESender == deSender && recv.DEDateTimeSent >= startDT && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on start time and end time
      else if (bStartTime && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent >= startDT && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id, DE Sender, and start time
      else if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender) && bStartTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DESender == deSender && recv.DEDateTimeSent >= startDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id and start time
      else if (!string.IsNullOrWhiteSpace(deID) && bStartTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DEDateTimeSent >= startDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Sender and start time
      else if (!string.IsNullOrWhiteSpace(deSender) && bStartTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DESender == deSender && recv.DEDateTimeSent >= startDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on start time
      else if (bStartTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent >= startDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id, DE Sender and end time
      else if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender) && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DESender == deSender && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id and end time
      else if (!string.IsNullOrWhiteSpace(deID) && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Sender and end time
      else if (!string.IsNullOrWhiteSpace(deSender) && bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DESender == deSender && recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on end time
      else if (bEndTime)
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEDateTimeSent <= endDT
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id and DE Sender
      else if (!string.IsNullOrWhiteSpace(deID) && !string.IsNullOrWhiteSpace(deSender))
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID && recv.DESender == deSender
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Id
      else if (!string.IsNullOrWhiteSpace(deID))
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DEId == deID
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on DE Sender
      else if (!string.IsNullOrWhiteSpace(deSender))
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      where recv.DESender == deSender
                      select msg;

        msgList = varData.ToList<Message>();
      }
      //match on everything
      else
      {
        var varData = from msg in linqDB.Messages
                      join recv in linqDB.Receiveds on msg.ReceivedId equals recv.Id
                      select msg;

        msgList = varData.ToList<Message>();
      }

      foreach (Message recvd in msgList)
      {
        mylist.Add(recvd.Body);
      }

      return mylist;
    }


    /// <summary>
    /// Creates KML based on the passed in information
    /// </summary>
    /// <param name="xmlWriter">XML Writer to hold KML xml</param>
    /// <param name="items">Data to create KML for</param>
    public static void GetKMLForDEList(XmlWriter xmlWriter, List<XElement> items)
    {
      foreach (XElement item in items)
      {
        GetKMLForDE(xmlWriter, item);
      }
    }

    /// <summary>
    /// Creates KML based on the passed in information
    /// </summary>
    /// <param name="xmlWriter">XML Writer to hold KML xml</param>
    /// <param name="items">Data to create KML for</param>
    public static void GetPlaybackKMLForDEList(XmlWriter xmlWriter, List<XElement> items)
    {
      List<KMLInfo> kmlInfoList;
      Dictionary<string, Dictionary<KMLInfo.KMLTypeEnum, List<KMLInfo>>> deInfo = new Dictionary<string, Dictionary<KMLInfo.KMLTypeEnum, List<KMLInfo>>>();
      Dictionary<string, Dictionary<string, List<KMLInfo>>> cotPOIInfo = new Dictionary<string, Dictionary<string, List<KMLInfo>>>();

      HashSet<ICNETStyle> usedStyles = new HashSet<ICNETStyle>();
      foreach (XElement item in items)
      {
        EDXLDE de = new EDXLDE(item.ToString(SaveOptions.None));

        kmlInfoList = new List<KMLInfo>();
        GetPlaybackKMLForDE(usedStyles, kmlInfoList, de);

        foreach (KMLInfo kmlInfoItem in kmlInfoList)
        {
          if (kmlInfoItem.KMLType != KMLInfo.KMLTypeEnum.POI)
          {
            if (!deInfo.ContainsKey(de.SenderID))
            {
              //add a new DE Sender
              deInfo.Add(de.SenderID, new Dictionary<KMLInfo.KMLTypeEnum, List<KMLInfo>>());
            }

            if (!deInfo[de.SenderID].ContainsKey(kmlInfoItem.KMLType))
            {
              //add a new KML Type
              deInfo[de.SenderID].Add(kmlInfoItem.KMLType, new List<KMLInfo>());
            }
            deInfo[de.SenderID][kmlInfoItem.KMLType].Add(kmlInfoItem);
          }
          else //group CoT POI by Sender and Distribution ID
          {
            if (!cotPOIInfo.ContainsKey(de.SenderID))
            {
              //add a new DE Sender
              cotPOIInfo.Add(de.SenderID, new Dictionary<string, List<KMLInfo>>());
            }

            if (!cotPOIInfo[de.SenderID].ContainsKey(de.DistributionID))
            {
              //add a new KML Type
              cotPOIInfo[de.SenderID].Add(de.DistributionID, new List<KMLInfo>());
            }
            cotPOIInfo[de.SenderID][de.DistributionID].Add(kmlInfoItem);
          }
        }
      }

      foreach (string deKey in deInfo.Keys)
      {
        Dictionary<KMLInfo.KMLTypeEnum, List<KMLInfo>> deKML = deInfo[deKey];

        xmlWriter.WriteStartElement("Folder");
        xmlWriter.WriteElementString("name", deKey);
        xmlWriter.WriteElementString("open", "0");

        string sDesc = "";

        if (deKML.ContainsKey(KMLInfo.KMLTypeEnum.Location))
        {
          sDesc = deKML[KMLInfo.KMLTypeEnum.Location][0].Description;
        }
        xmlWriter.WriteElementString("description", sDesc);

        foreach (KMLInfo.KMLTypeEnum kmlKey in deKML.Keys)
        {
          xmlWriter.WriteStartElement("Folder");
          xmlWriter.WriteElementString("name", GetEnumName(kmlKey));
          xmlWriter.WriteElementString("open", "0");

          List<KMLInfo> kmlList = deKML[kmlKey];

          foreach (KMLInfo kml in kmlList)
          {
            XmlReader xmlReader = XmlReader.Create(new StringReader(kml.KMLString));

            xmlWriter.WriteNode(xmlReader, true);
          }

          xmlWriter.WriteEndElement();
        }


        xmlWriter.WriteEndElement();
      }

      foreach (string deSender in cotPOIInfo.Keys)
      {
        Dictionary<string, List<KMLInfo>> deKML = cotPOIInfo[deSender];

        xmlWriter.WriteStartElement("Folder");
        xmlWriter.WriteElementString("name", deSender);
        xmlWriter.WriteElementString("open", "0");

        xmlWriter.WriteStartElement("Folder");
        xmlWriter.WriteElementString("name", GetEnumName(KMLInfo.KMLTypeEnum.POI));
        xmlWriter.WriteElementString("open", "0");

        foreach (string deId in deKML.Keys)
        {
          xmlWriter.WriteStartElement("Folder");
          string deIdFixed = deKML[deId][0].DEId;
          deIdFixed = deIdFixed.Replace("CoTEvent-", ""); //TODO: clean up later
          xmlWriter.WriteElementString("name", deIdFixed);
          xmlWriter.WriteElementString("open", "0");
          xmlWriter.WriteElementString("description", deKML[deId][0].Description);

          List<KMLInfo> kmlList = deKML[deId];

          foreach (KMLInfo kml in kmlList)
          {
            XmlReader xmlReader = XmlReader.Create(new StringReader(kml.KMLString));

            xmlWriter.WriteNode(xmlReader, true);
          }

          xmlWriter.WriteEndElement();
        }

        xmlWriter.WriteEndElement();
        xmlWriter.WriteEndElement();
      }
      //KMLDal.WriteStyles(usedStyles, xmlWriter);
    }

    /// <summary>
    /// Translate KMLInfo KML Type enum into a string
    /// </summary>
    /// <param name="eVal">enum to translate</param>
    /// <returns>translated string</returns>
    private static string GetEnumName(KMLInfo.KMLTypeEnum eVal)
    {
      switch (eVal)
      {
        case KMLInfo.KMLTypeEnum.Cap:
          return "Alerts";
        case KMLInfo.KMLTypeEnum.Dispatch_Incident:
          return "Dispatch Incidents";
        case KMLInfo.KMLTypeEnum.Dispatch_Unit:
          return "Dispatch Units";
        case KMLInfo.KMLTypeEnum.Have:
          return "Hospital Availability";
        case KMLInfo.KMLTypeEnum.Image:
          return "Images";
        case KMLInfo.KMLTypeEnum.Location:
          return "Locations";
        case KMLInfo.KMLTypeEnum.Other:
          return "Custom";
        case KMLInfo.KMLTypeEnum.SitRep:
          return "Observations";
        case KMLInfo.KMLTypeEnum.Tep:
          return "Patient Tracking";
        case KMLInfo.KMLTypeEnum.POI:
          return "Points of Interest";
      }
      return "";
    }

    /// <summary>
    /// Creates the playback style kml for a DE
    /// </summary>
    /// <param name="usedStyles">KML Icon styles required for DE</param>
    /// <param name="kmlInfoList">KML for DE</param>
    /// <param name="de">DE to create KML for</param>
    private static void GetPlaybackKMLForDE(HashSet<ICNETStyle> usedStyles, List<KMLInfo> kmlInfoList, EDXLDE de)
    {
      CAP capmsg;
      EDXLHAVE havemsg;
      SitRep sitRepmsg;
      CoTWrapper cotmsg;

      XNamespace gml = "http://www.opengis.net/gml";

      foreach (ContentObject co in de.ContentObjects)
      {
        string dscString = de.DistributionID + de.SenderID + co.ContentDescription;
        byte[] b2 = System.Text.Encoding.ASCII.GetBytes(dscString);
        int DSCHash = ComputeHash(b2);

        StringBuilder xml = new StringBuilder();

        //get rid of xml header
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.ConformanceLevel = ConformanceLevel.Fragment;

        XmlWriter xmlWriter = XmlWriter.Create(xml, settings);

        if (co.XMLContent != null)
        {
          foreach (XElement doc in co.XMLContent.EmbeddedXMLContent)
          {
            string contentNS = doc.Name.NamespaceName;

            if (contentNS.Equals(EDXLConstants.CAP11Namespace) ||
              contentNS.ToString().Equals(EDXLConstants.CAP12Namespace))
            {
              capmsg = new CAP();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              capmsg.ReadXML(xdoc.FirstChild);
            }
            else if (contentNS.Equals(EDXLConstants.HAVE10Namespace))
            {
              havemsg = new EDXLHAVE();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              havemsg.ReadXML(xdoc.FirstChild);

            }
            else if (contentNS.Equals(EDXLConstants.SitRep10Namespace))
            {
              sitRepmsg = new SitRep();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              sitRepmsg.ReadXML(xdoc.FirstChild);
              string sDescription = GetPlaybackKMLForSitRep(usedStyles, xmlWriter, sitRepmsg, DSCHash, de);

              xmlWriter.Flush();

              KMLInfo saveKML = new KMLInfo();
              saveKML.KMLType = KMLInfo.KMLTypeEnum.SitRep;
              saveKML.DEId = de.DistributionID;
              saveKML.DESender = de.SenderID;
              saveKML.KMLString = xml.ToString();
              saveKML.Description = sDescription;

              kmlInfoList.Add(saveKML);
            }
            else if (contentNS.Equals(EDXLConstants.EDXLCoTNamespace))
            {
              cotmsg = new CoTWrapper();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }
              cotmsg.ReadXML(xdoc.FirstChild);
              string sDescription = "";

              KMLInfo.KMLTypeEnum cotEnum = KMLInfo.KMLTypeEnum.Location;

              //determine if CoT is POI from ICALL
              ICotDetailComponent details = cotmsg.CoTEvent.Detail.GetFirstElement("__icnet");
              if (details != null)
              {
                XmlNode node = details.XmlNode.SelectSingleNode("icall"); ;
                if (node != null)
                {
                  XmlAttribute attr = node.Attributes["editable"];

                  if (attr != null)
                  {
                    bool bEditable = false;

                    if (bool.TryParse(attr.Value, out bEditable))
                    {
                      if (bEditable)
                      {
                        cotEnum = KMLInfo.KMLTypeEnum.POI;
                      }
                    }
                  }
                }
              }

              //handle regular location CoT differently from POI CoT
              if (cotEnum == KMLInfo.KMLTypeEnum.Location)
              {
                sDescription = GetPlaybackKMLForCoTLocation(usedStyles, xmlWriter, cotmsg, DSCHash, de);
                xmlWriter.Flush();
              }
              else
              {
                sDescription = GetPlaybackKMLForCoTPOI(usedStyles, xmlWriter, cotmsg, DSCHash, de);
                xmlWriter.Flush();
              }

              KMLInfo saveKML = new KMLInfo();
              saveKML.KMLType = cotEnum;
              saveKML.DEId = de.DistributionID;
              saveKML.DESender = de.SenderID;
              saveKML.KMLString = xml.ToString();
              saveKML.Description = sDescription;

              kmlInfoList.Add(saveKML);
            }
            else // handles all other xml types
            {
              ValueList contentKeywordVL = null;

              foreach (ValueList VL in co.ContentKeyword)
              {
                if (VL.ValueListURN.Equals(EDXLConstants.ContentKeywordListName))
                {
                  contentKeywordVL = VL;
                  break;
                }
              }

              if (contentKeywordVL != null)
              {
                OtherXMLWrapper xmlMsg = new OtherXMLWrapper(contentKeywordVL.Value, co.ContentDescription);
                XmlDocument xdoc = new XmlDocument();
                using (XmlReader xr = doc.CreateReader())
                {
                  xdoc.Load(xr);
                }

                xmlMsg.ReadXML(xdoc.FirstChild);
              }
            }
          }
        }
        else if (co.NonXMLContent != null)
        {
          string sDescription = GetPlaybackKMLForNonXMLContent(usedStyles, xmlWriter, de, co, DSCHash);

          xmlWriter.Flush();

          KMLInfo saveKML = new KMLInfo();
          saveKML.KMLType = KMLInfo.KMLTypeEnum.Image;
          saveKML.DEId = de.DistributionID;
          saveKML.DESender = de.SenderID;
          saveKML.KMLString = xml.ToString();
          saveKML.Description = sDescription;

          kmlInfoList.Add(saveKML);
        }
      }
    }

    /// <summary>
    /// Creates KML based on the passed in information
    /// </summary>
    /// <param name="xmlWriter">XML Writer to hold KML xml</param>
    /// <param name="item">Data to create KML for</param>
    public static void GetKMLForDE(XmlWriter xmlWriter, XElement item)
    {
      EDXLDE de = new EDXLDE(item.ToString(SaveOptions.None));

      foreach (ContentObject co in de.ContentObjects)
      {
        string dcsHash = DEDalUtils.ComputeHash(de.DistributionID, de.SenderID, co.ContentDescription).ToString();
        string kml = GISConverter.CreateKMLForContentObject(de, co, dcsHash);
        xmlWriter.WriteString(kml);
      }
    }

    /// <summary>
    /// Create GeoRSS list for DEs
    /// </summary>
    /// <param name="items">DEs</param>
    /// <returns>GeoRSS list</returns>
    public static List<SyndicationItem> GetGeoRSSForDEList(List<XElement> items)
    {
      List<SyndicationItem> synItems = new List<SyndicationItem>();

      foreach (XElement item in items)
      {
        GetGeoRSSForDE(synItems, item);
      }

      return synItems;
    }

    /// <summary>
    /// Create GeoRSS for DE
    /// </summary>
    /// <param name="synItems">GeoRSS list</param>
    /// <param name="item">DE to convert</param>
    public static void GetGeoRSSForDE(List<SyndicationItem> synItems, XElement item)
    {
      CAP capmsg;
      EDXLHAVE havemsg;
      SitRep sitRepmsg;
      CoTWrapper cotmsg;

      XNamespace gml = "http://www.opengis.net/gml";

      EDXLDE de = new EDXLDE(item.ToString(SaveOptions.None));

      foreach (ContentObject co in de.ContentObjects)
      {
        string dscString = de.DistributionID + de.SenderID + co.ContentDescription;
        byte[] b2 = System.Text.Encoding.ASCII.GetBytes(dscString);
        int DSCHash = ComputeHash(b2);

        if (co.XMLContent != null)
        {
          foreach (XElement doc in co.XMLContent.EmbeddedXMLContent)
          {
            string contentNS = doc.Name.NamespaceName;

            if (contentNS.Equals(EDXLConstants.CAP11Namespace) ||
              contentNS.ToString().Equals(EDXLConstants.CAP12Namespace))
            {
              capmsg = new CAP();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              capmsg.ReadXML(xdoc.FirstChild);
            }
            else if (contentNS.Equals(EDXLConstants.HAVE10Namespace))
            {
              havemsg = new EDXLHAVE();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              havemsg.ReadXML(xdoc.FirstChild);

            }
            else if (contentNS.Equals(EDXLConstants.SitRep10Namespace))
            {
              sitRepmsg = new SitRep();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              sitRepmsg.ReadXML(xdoc.FirstChild);
              GetGeoRSSForSitRep(synItems, sitRepmsg, DSCHash, de);
            }
            else if (contentNS.Equals(EDXLConstants.EDXLCoTNamespace))
            {
              cotmsg = new CoTWrapper();
              XmlDocument xdoc = new XmlDocument();
              using (XmlReader xr = doc.CreateReader())
              {
                xdoc.Load(xr);
              }

              cotmsg.ReadXML(xdoc.FirstChild);
              GetGeoRSSForCoT(synItems, cotmsg, DSCHash, de);
            }
            else // handles all other xml types
            {
              ValueList contentKeywordVL = null;

              foreach (ValueList VL in co.ContentKeyword)
              {
                if (VL.ValueListURN.Equals(EDXLConstants.ContentKeywordListName))
                {
                  contentKeywordVL = VL;
                  break;
                }
              }

              if (contentKeywordVL != null)
              {
                OtherXMLWrapper xmlMsg = new OtherXMLWrapper(contentKeywordVL.Value, co.ContentDescription);
                XmlDocument xdoc = new XmlDocument();
                using (XmlReader xr = doc.CreateReader())
                {
                  xdoc.Load(xr);
                }

                xmlMsg.ReadXML(xdoc.FirstChild);
              }
            }
          }
        }
        else if (co.NonXMLContent != null)
        {
          GetGeoRSSForNonXMLContent(synItems, co, DSCHash, de);
        }
      }
    }

    #endregion
    #region Private Methods

    /// <summary>
    /// Submits changes to the database.
    /// </summary>
    /// <param name="linqDB">The database to which changes should be submitted. </param>
    private static void Submit(EDXLHistoryDALDataContext linqDB)
    {
      try
      {
        linqDB.SubmitChanges();
      }
      catch (Exception)
      {
        // it is OK for this to fail right now because not all deployments have the LOGGINGDB db deployed
      }
    }

    /// <summary>
    /// Create hash for supplied data
    /// </summary>
    /// <param name="data">Data to hash</param>
    /// <returns>Hash Int</returns>
    private static int ComputeHash(byte[] data)
    {
      unchecked
      {
        const int p = 16777619;
        int hash = (int)2166136261;

        for (int i = 0; i < data.Length; i++)
          hash = (hash ^ data[i]) * p;

        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        return hash;
      }
    }

    /// <summary>
    /// Create syndication item for CoT message
    /// </summary>
    /// <param name="synItems">Syndication item list to add to</param>
    /// <param name="cotmsg">CoT message to convert</param>
    /// <param name="DSCHash">ICNET hash for CoT message</param>
    /// <param name="de">Parent DE</param>
    private static void GetGeoRSSForCoT(List<SyndicationItem> synItems, CoTWrapper cotmsg, int DSCHash, EDXLDE de)
    {
      //<feed xmlns="http://www.w3.org/2005/Atom" xmlns:icnet="http://icnet.mitre.org" xmlns:georss="http://www.georss.org/georss">
      //  <title type="Text">IC.NET History DE Feed: </title>
      //  <Id>uuid:1d0c33da-fd21-4f07-b8a7-c2b2d6299338;Id=1</Id>
      //  <updated>2013-01-20T15:03:54Z</updated>
      //  <link rel="self" type="application/atom+xml" href="http://localhost:21533/HistoryService.svc/georss/de?sender=FPS.RCNTF%20Skrtic@c3ib.org"/>
        //<entry xml:base="http://icnet-test.mitre.org/">
        //  <Id>1414799163</Id>
        //  <title type="Text">NYSP.H116</title>
        //  <summary type="Text">a-f-A-C-H-e-f</summary>
        //  <published>2013-02-12T01:18:00-05:00</published>
        //  <updated>2013-02-12T06:18:01-05:00</updated>
        //  <author>
      //      <name>FPS.RCNTF Skrtic@c3ib.org</name>
      //      <email>FPS.RCNTF Skrtic@c3ib.org</email>
        //  </author>
        //  <link href="http://icnet-test.mitre.org/DataService.svc/HTML/1414799163"/>
        //  <link rel="alternate" type="Text/xml" title="Download Link" length="1000" href="http://icnet-test.mitre.org/DataService.svc/XML/1414799163"/>
        //  <content type="Text">a-f-A-C-H-e-f</content>
        //  <rights type="Text">Copyright (c) 2010 The MITRE Corporation. All rights reserved.</rights>
        //  <georss:point xmlns:georss="http://www.georss.org/georss">38.98107 -77.34483</georss:point>
        //  <icnet:number/>
        //  <icnet:battery>1</icnet:battery>
        //  <icnet:signal/>
        //</entry>
      //</feed>
      CotEvent evt = cotmsg.CoTEvent;

      SyndicationItem synItem = new SyndicationItem();
      synItem.Id = DSCHash.ToString();
      synItem.Title = new TextSyndicationContent(GetTitleForCoT(evt));

      string sFriendlyName = evt.Type;

      //TODO fix this
      ICNETStyle style = new ICNETStyle();// KMLStyleEngine.GetStyle(cotmsg);

      if (style != null && !String.IsNullOrWhiteSpace(style.KMLStyleFriendlyName))
      {
        sFriendlyName = style.KMLStyleFriendlyName;
      }

      synItem.Summary = new TextSyndicationContent(sFriendlyName);
      synItem.PublishDate = evt.Stale;
      synItem.LastUpdatedTime = evt.Time;
      synItem.Authors.Add(new SyndicationPerson(de.SenderID, de.SenderID, String.Empty));
      synItem.Links.Add(new SyndicationLink(new Uri(ICNETSOAConstants.ICNETdatalinkToHistoryDEHTML +
        "?Id=" + de.DistributionID + "&Sender=" + de.SenderID + "&DateTime=" + de.DateTimeSent.ToLocalTime().ToString() )));
      synItem.Content = new TextSyndicationContent(sFriendlyName);
      synItem.Copyright = new TextSyndicationContent(EDXLConstants.SyndicationCopyright);

      XNamespace ns = EDXLConstants.GeoRSSNamespace;
      XElement element = new XElement(ns + "point");
      element.Value = evt.Point.Latitude.ToString() + " " + evt.Point.Longitude.ToString();
      synItem.ElementExtensions.Add(element);

      GetGeoRSSExtensionFromCoT(synItem, evt);

      synItems.Add(synItem);
    }

    /// <summary>
    /// Create syndication item for SitRep message
    /// </summary>
    /// <param name="synItems">Syndication item list to add to</param>
    /// <param name="sitRepmsg">SitRep message to convert</param>
    /// <param name="DSCHash">ICNET hash for SitRep message</param>
    /// <param name="de">Parent DE</param>
    private static void GetGeoRSSForSitRep(List<SyndicationItem> synItems, SitRep sitRepmsg, int DSCHash, EDXLDE de)
    {
      //<feed xmlns="http://www.w3.org/2005/Atom" xmlns:icnet="http://icnet.mitre.org" xmlns:georss="http://www.georss.org/georss">
      //  <title type="Text">IC.NET History DE Feed: </title>
      //  <Id>uuid:1d0c33da-fd21-4f07-b8a7-c2b2d6299338;Id=1</Id>
      //  <updated>2013-01-20T15:03:54Z</updated>
      //  <link rel="self" type="application/atom+xml" href="http://localhost:21533/HistoryService.svc/georss/de?sender=FPS.RCNTF%20Skrtic@c3ib.org"/>
        //  <entry xml:base="http://icnet-test.mitre.org/">
        //    <Id>-1540957385</Id>
        //    <title type="Text">Field Observation - SuspiciousPerson</title>
        //    <summary type="Text">MessageID: 50EEA7D5-B02C-441E-A524-65D6082B9BBE</summary>
        //    <published>2013-02-12T01:10:09-05:00</published>
        //    <updated>2013-02-12T06:10:09-05:00</updated>
        //    <author>
        //      <name>FPS.RCNTF Skrtic@c3ib.org</name>
        //      <email>FPS.RCNTF Skrtic@c3ib.org</email>
        //    </author>
        //    <link href="http://icnet-test.mitre.org/DataService.svc/HTML/-1540957385"/>
        //    <link rel="alternate" type="Text/xml" title="Download Link" length="1000" href="http://icnet-test.mitre.org/DataService.svc/XML/-1540957385"/>
        //    <content type="Text">Observation: Ttt
        //Immediate Needs: </content>
        //    <rights type="Text">Copyright (c) 2010 The MITRE Corporation. All rights reserved.</rights>
        //    <georss:point xmlns:georss="http://www.georss.org/georss">38.968 -77.3123</georss:point>
        //  </entry>
      //</feed>

      string sTitle = GetTitleForSitRep(sitRepmsg);
      string sFriendlyName = "Field Observation"; //TODO: clean up this HACK

      ICNETStyle style = new ICNETStyle();// KMLStyleEngine.GetStyleFromContentOrTitle(sFriendlyName, sTitle);

      if (style != null && !String.IsNullOrWhiteSpace(style.KMLStyleFriendlyName))
      {
        sFriendlyName = style.KMLStyleFriendlyName;
      }
      SyndicationItem synItem = new SyndicationItem();
      synItem.Id = DSCHash.ToString();

      synItem.Title = new TextSyndicationContent(sTitle);

      synItem.Summary = new TextSyndicationContent(sFriendlyName);
      synItem.PublishDate = sitRepmsg.FromDateTime;
      synItem.LastUpdatedTime = sitRepmsg.ToDateTime;
      synItem.Authors.Add(new SyndicationPerson(de.SenderID, de.SenderID, String.Empty));
      synItem.Links.Add(new SyndicationLink(new Uri(ICNETSOAConstants.ICNETdatalinkToHistoryDEHTML +
        "?Id=" + de.DistributionID + "&Sender=" + de.SenderID + "&DateTime=" + de.DateTimeSent.ToLocalTime().ToString())));

      synItem.Content = new TextSyndicationContent("Observation - " + GetReportTextForSitRep(sitRepmsg));
      synItem.Copyright = new TextSyndicationContent(EDXLConstants.SyndicationCopyright);

      GMLPoint gmlPoint = sitRepmsg.ReportLocation.Location as GMLPoint;
      if (gmlPoint != null)
      {
        string latlon = gmlPoint.Pos.ToString();
        string[] coords = latlon.Split(' ');
        int lonIndex = 1;
        int latIndex = 0;

        XNamespace ns = EDXLConstants.GeoRSSNamespace;
        XElement element = new XElement(ns + "point");
        element.Value = coords[latIndex] + "," + coords[lonIndex];
        synItem.ElementExtensions.Add(element);
      }

      synItems.Add(synItem);
    }

    /// <summary>
    /// Create syndication item for non XML content
    /// </summary>
    /// <param name="synItems">Syndication item list to add to</param>
    /// <param name="co">non XML content to convert</param>
    /// <param name="DSCHash">ICNET hash for non XML content</param>
    /// <param name="de">Parent DE</param>
    private static void GetGeoRSSForNonXMLContent(List<SyndicationItem> synItems, ContentObject co, int DSCHash, EDXLDE de)
    {
      //<feed xmlns="http://www.w3.org/2005/Atom" xmlns:icnet="http://icnet.mitre.org" xmlns:georss="http://www.georss.org/georss">
      //  <title type="Text">IC.NET History DE Feed: </title>
      //  <Id>uuid:1d0c33da-fd21-4f07-b8a7-c2b2d6299338;Id=1</Id>
      //  <updated>2013-01-20T15:03:54Z</updated>
      //  <link rel="self" type="application/atom+xml" href="http://localhost:21533/HistoryService.svc/georss/de?sender=FPS.RCNTF%20Skrtic@c3ib.org"/>
      //  <entry>
      //    <Id>1699155407</Id>
      //    <title type="Text">SitRep Image 1 [FPS.RCNTF Skrtic@c3ib.org,SitRep20 Jan 2013 15:03:54 GMT]</title>
      //    <summary type="Text">image/jpeg</summary>
      //    <published>2013-01-20T15:03:54Z</published>
      //    <updated>2013-01-20T15:03:54Z</updated>
      //    <author>
      //      <name>FPS.RCNTF Skrtic@c3ib.org</name>
      //      <email>FPS.RCNTF Skrtic@c3ib.org</email>
      //    </author>
      //    <link href="http://localhost:21533/DataService.svc/History/MIME?Id=SitRep20%20Jan%202013%2015:03:54%20GMT&amp;Sender=FPS.RCNTF%20Skrtic@c3ib.org&amp;DateTime=1/20/2013%2010:03:54%20AM&amp;ContentDescription=SitRep%20Image%201%20%5BFPS.RCNTF%20Skrtic@c3ib.org,SitRep20%20Jan%202013%2015:03:54%20GMT%5D"/>
      //    <content type="Text">image/jpeg</content>
      //    <rights type="Text">Copyright (c) 2010 The MITRE Corporation. All rights reserved.</rights>
      //    <georss:point>-77.01010604999999 38.866690649999995</georss:point>
      //  </entry>
      //</feed>

      SyndicationItem synItem = new SyndicationItem();
      synItem.Id = DSCHash.ToString();
      synItem.Title = new TextSyndicationContent(co.ContentDescription);
      synItem.Summary = new TextSyndicationContent(co.NonXMLContent.MIMEType);
      synItem.PublishDate = de.DateTimeSent;
      synItem.LastUpdatedTime = de.DateTimeSent;
      synItem.Authors.Add(new SyndicationPerson(de.SenderID, de.SenderID, String.Empty));
      synItem.Links.Add(new SyndicationLink(new Uri(ICNETSOAConstants.ICNETdatalinkToHistoryMIME +
        "?Id=" + de.DistributionID + "&Sender=" + de.SenderID + "&DateTime=" + de.DateTimeSent.ToLocalTime().ToString() + "&ContentDescription=" + co.ContentDescription)));
      synItem.Content = new TextSyndicationContent(co.NonXMLContent.MIMEType);
      synItem.Copyright = new TextSyndicationContent(EDXLConstants.SyndicationCopyright);

      StringBuilder output = new StringBuilder();
      XmlWriterSettings xsettings = new XmlWriterSettings();
      xsettings.Indent = true;
      xsettings.IndentChars = "\t";
      xsettings.OmitXmlDeclaration = true;
      XmlWriter xmlWriter = XmlWriter.Create(output, xsettings);

      string point = de.TargetArea[0].Circle[0];

      if (point != null)
      {
        string latlon = point.Split(' ')[0];
        string[] coords = latlon.Split(',');
        int lonIndex = 1;
        int latIndex = 0;
        xmlWriter.WriteStartElement(EDXLConstants.GeoRSSPrefix, "point", EDXLConstants.GeoRSSNamespace);
        xmlWriter.WriteString(coords[latIndex] + " " + coords[lonIndex]);
        xmlWriter.WriteEndElement();
      }

      xmlWriter.Flush();
      xmlWriter.Close();
      MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(output.ToString()));
      synItem.ElementExtensions.Add(XmlReader.Create(ms));
        
      synItems.Add(synItem);
    }

  
    /// <summary>
    /// Get observation Text from SitRep message
    /// </summary>
    /// <param name="sitRepmsg">SitRep message</param>
    /// <returns>Observation Text</returns>
    private static string GetReportTextForSitRep(SitRep sitRepmsg)
    {
      string sText = "None Entered";

      if (sitRepmsg.MessageReportType.HasValue)
      {
        if (sitRepmsg.MessageReportType == SitRepReportType.FieldObservation)
        {
          SituationObservation sitob = sitRepmsg.Report as SituationObservation;

          if (sitob != null)
          {
            sText = sitob.ObservationText;
          }
        }
        //TODO: support other message report types
      }

      return sText;
    }

    /// <summary>
    /// Get title from SitRep message
    /// </summary>
    /// <param name="sitRepmsg">SitRep message</param>
    /// <returns>SitRep title</returns>
    private static string GetTitleForSitRep(SitRep sitRepmsg)
    {
      string sTitle = "Field Observation";

      if (sitRepmsg.MessageReportType.HasValue)
      {
        if (sitRepmsg.MessageReportType == SitRepReportType.FieldObservation)
        {
          SituationObservation sitob = sitRepmsg.Report as SituationObservation;

          if (sitob != null)
          {
            if (sitob.ObservationType.HasValue)
            {
              sTitle = "Field Observation - " + sitob.ObservationType.ToString();
            }
          }
        }
        //TODO: support other message report types
      }

      return sTitle;
    }

    /// <summary>
    /// Get report type from SitRep message
    /// </summary>
    /// <param name="sitRepmsg">SitRep message</param>
    /// <returns>SitRep report type</returns>
    private static string GetTypeForSitRep(SitRep sitRepmsg)
    {
      string sType = "GeneralObservation";

      if (sitRepmsg.MessageReportType.HasValue)
      {
        if (sitRepmsg.MessageReportType == SitRepReportType.FieldObservation)
        {
          SituationObservation sitob = sitRepmsg.Report as SituationObservation;

          if (sitob != null)
          {
            if (sitob.ObservationType.HasValue)
            {
              sType = sitob.ObservationType.ToString();
            }
          }
        }
        //TODO: support other message report types
      }

      return sType;
    }

    //TODO remove
    private class ICNETStyle { public string KMLStyleFriendlyName { get; set; } public string KMLStyleName { get; set; } }

    /// <summary>
    /// Get KML for playback from non XML content
    /// </summary>
    /// <param name="usedStyles">KML Icon styles</param>
    /// <param name="xmlWriter">XML Writer to write KML to</param>
    /// <param name="de">DE parent</param>
    /// <param name="co">non XML content</param>
    /// <param name="DSCHash">ICNET hash of non XML content</param>
    /// <returns>description of non XML content</returns>
    private static string GetPlaybackKMLForNonXMLContent(HashSet<ICNETStyle> usedStyles, XmlWriter xmlWriter, EDXLDE de, ContentObject co, int DSCHash)
    {
      //SAMPLE CoT KML
      //<Placemark>
      //  <name>Image - MITRE.dmcgarry</name>
      //  <TimeStamp>
      //    <when>2005-08-21T09:01:00Z</when>
      //  </TimeStamp>
      //  <styleUrl>#RECON TEAM</styleUrl>
      //  <Point>
      //    <coordinates>55.374000,-4.640000</coordinates>
      //  </Point>
      //</Placemark

      string styleID = string.Empty;
      string sFriendlyName = "Image"; //TODO: clean up this HACK

      //TODO fix this
      ICNETStyle style = new ICNETStyle();// KMLStyleEngine.GetStyleFromContentOrTitle("image", "image");

      if (style != null)
      {
        //usedStyles.AddDependencies(style);
        styleID = @"#" + style.KMLStyleName;

        if (!String.IsNullOrWhiteSpace(style.KMLStyleFriendlyName))
        {
          sFriendlyName = style.KMLStyleFriendlyName;
        }
      }
      else
      {
        styleID = string.Empty;// KMLStyleEngine.DefaultStyleId;
      }

      xmlWriter.WriteStartElement("Placemark");
      string sender = de.SenderID.Substring(0, de.SenderID.IndexOf("@"));

      xmlWriter.WriteElementString("name", "Image - " + sender);
      xmlWriter.WriteElementString("snippet", "");

      xmlWriter.WriteStartElement("description");

      Uri uriParams = new Uri(ICNETSOAConstants.ICNETdatalinkToHistoryMIME + "?Id=" + de.DistributionID + "&Sender=" + de.SenderID + "&DateTime=" + de.DateTimeSent.ToLocalTime().ToString() + "&ContentDescription=" + co.ContentDescription);
      string sMIMELink = uriParams.AbsoluteUri;

      xmlWriter.WriteCData("<img alt=\"Embedded Image\" src=\"" + sMIMELink + "\"/><br/>");
      xmlWriter.WriteEndElement(); //close description

      xmlWriter.WriteStartElement("TimeStamp");
      string zuluTimeAsString = de.DateTimeSent.ToString("u");
      zuluTimeAsString = zuluTimeAsString.Replace(' ', 'T');
      xmlWriter.WriteElementString("when", zuluTimeAsString);
      xmlWriter.WriteEndElement(); //close TimeStamp

      xmlWriter.WriteElementString("styleUrl", styleID);
      xmlWriter.WriteStartElement("Point");
      xmlWriter.WriteStartElement("coordinates");
      string point = de.TargetArea[0].Circle[0];

      if (point != null)
      {
        string latlon = point.Split(' ')[0];
        string[] coords = latlon.Split(',');
        int lonIndex = 1;
        int latIndex = 0;
        xmlWriter.WriteString(coords[lonIndex] + "," + coords[latIndex]); //OASIS GML has point lat and lon backwards to normal GML standard 
      }

      xmlWriter.WriteEndElement(); //close coordinates
      xmlWriter.WriteEndElement(); //close point

      xmlWriter.WriteEndElement(); //close placemark

      return sFriendlyName;
    }

    /// <summary>
    /// Get KML for playback from SitRep message
    /// </summary>
    /// <param name="usedStyles">KML Icon styles</param>
    /// <param name="xmlWriter">XML Writer to write KML to</param>
    /// <param name="de">DE parent</param>
    /// <param name="sitRepMsg">SitRep message</param>
    /// <param name="DSCHash">ICNET hash of SitRep message</param>
    /// <returns>description of SitRep message</returns>
    private static string GetPlaybackKMLForSitRep(HashSet<ICNETStyle> usedStyles, XmlWriter xmlWriter, SitRep sitRepMsg, int DSCHash, EDXLDE de)
    {
      //SAMPLE CoT KML
      //<Placemark>
      //  <name>FieldObservation - MITRE.dmcgarry</name>
      //  <TimeStamp>
      //    <when>2005-08-21T09:01:00Z</when>
      //  </TimeStamp>
      //  <styleUrl>#RECON TEAM</styleUrl>
      //  <Point>
      //    <coordinates>55.374000,-4.640000</coordinates>
      //  </Point>
      //</Placemark>

      xmlWriter.WriteStartElement("Placemark");

      string styleID = string.Empty;
      string sFriendlyName = "Field Observation"; //TODO: clean up this HACK

      string sTitle = GetTitleForSitRep(sitRepMsg);
      ICNETStyle style = new ICNETStyle();// KMLStyleEngine.GetStyleFromContentOrTitle(sFriendlyName, sTitle);

      if (style != null)
      {
        //usedStyles.AddDependencies(style);
        styleID = @"#" + style.KMLStyleName;

        if (!String.IsNullOrWhiteSpace(style.KMLStyleFriendlyName))
        {
          sFriendlyName = style.KMLStyleFriendlyName;
        }
      }
      else
      {
        styleID = string.Empty;// KMLStyleEngine.DefaultStyleId;
      }
      string sender = de.SenderID.Substring(0, de.SenderID.IndexOf("@"));

      xmlWriter.WriteElementString("name", GetTypeForSitRep(sitRepMsg) + " - " + sender);
      xmlWriter.WriteElementString("snippet", "");

      xmlWriter.WriteStartElement("description");
      StringBuilder sbDescription = new StringBuilder(GetReportTextForSitRep(sitRepMsg) + "<br/><br/>");

      Uri uriParams = new Uri(ICNETSOAConstants.ICNETdatalinkToHistoryDEHTML + "?Id=" + de.DistributionID + "&Sender=" + de.SenderID + "&DateTime=" + de.DateTimeSent.ToLocalTime().ToString());
      string sLink = uriParams.AbsoluteUri;

      sbDescription.Append("<a href=\"" + sLink + "\">Details</a><br/>");

      xmlWriter.WriteCData(sbDescription.ToString());
      xmlWriter.WriteEndElement(); //close description

      xmlWriter.WriteStartElement("TimeStamp");
      string zuluTimeAsString = de.DateTimeSent.ToString("u");
      zuluTimeAsString = zuluTimeAsString.Replace(' ', 'T');
      xmlWriter.WriteElementString("when", zuluTimeAsString);
      xmlWriter.WriteEndElement(); //close TimeStamp

      xmlWriter.WriteElementString("styleUrl", styleID);
      xmlWriter.WriteStartElement("Point");
      xmlWriter.WriteStartElement("coordinates");
      GMLPoint gmlPoint = sitRepMsg.ReportLocation.Location as GMLPoint;

      if (gmlPoint != null)
      {
        string latlon = gmlPoint.Pos.ToString();
        string[] coords = latlon.Split(' ');
        int lonIndex = 1;
        int latIndex = 0;
        xmlWriter.WriteString(coords[lonIndex] + "," + coords[latIndex]); //OASIS GML has point lat and lon backwards to normal GML standard 
      }

      xmlWriter.WriteEndElement(); //close coordinates
      xmlWriter.WriteEndElement(); //close point

      xmlWriter.WriteEndElement(); //close placemark

      return sFriendlyName;
    }

    /// <summary>
    /// Get KML for playback from CoT message
    /// </summary>
    /// <param name="usedStyles">KML Icon styles</param>
    /// <param name="xmlWriter">XML Writer to write KML to</param>
    /// <param name="de">DE parent</param>
    /// <param name="sitRepMsg">CoT message</param>
    /// <param name="DSCHash">ICNET hash of CoT message</param>
    /// <returns>description of CoT message</returns>
    private static string GetPlaybackKMLForCoTLocation(HashSet<ICNETStyle> usedStyles, XmlWriter xmlWriter, CoTWrapper cotmsg, int DSCHash, EDXLDE de)
    {
      //SAMPLE CoT KML
      //<Placemark>
      //  <name>MITRE.dmcgarry/name>
      //  <TimeStamp>
      //    <when>2005-08-21T09:01:00Z</when>
      //  </TimeStamp>
      //  <styleUrl>#RECON TEAM</styleUrl>
      //  <Point>
      //    <coordinates>55.374000,-4.640000</coordinates>
      //  </Point>
      //</Placemark>

      CotEvent evt = cotmsg.CoTEvent;

      xmlWriter.WriteStartElement("Placemark");

      string sender = de.SenderID.Substring(0, de.SenderID.IndexOf("@"));
      string localTimeAsString = evt.Time.ToLocalTime().ToString();
      xmlWriter.WriteElementString("name", sender);
      xmlWriter.WriteElementString("snippet", "");

      xmlWriter.WriteStartElement("TimeStamp");
      string zuluTimeAsString = evt.Time.ToString("u");
      zuluTimeAsString = zuluTimeAsString.Replace(' ', 'T');
      xmlWriter.WriteElementString("when", zuluTimeAsString);
      xmlWriter.WriteEndElement(); //close TimeStamp

      string styleID = string.Empty;
      string sFriendlyName = evt.Type;

      ICNETStyle style = new ICNETStyle();// KMLStyleEngine.GetStyle(cotmsg);

      if (style != null)
      {
        //usedStyles.AddDependencies(style);
        styleID = @"#" + style.KMLStyleName;

        if (!String.IsNullOrWhiteSpace(style.KMLStyleFriendlyName))
        {
          sFriendlyName = style.KMLStyleFriendlyName;
        }
      }
      else
      {
        styleID = string.Empty;// KMLStyleEngine.DefaultStyleId;
      }

      xmlWriter.WriteElementString("styleUrl", styleID);

      xmlWriter.WriteStartElement("Point");
      xmlWriter.WriteStartElement("coordinates");
      xmlWriter.WriteString(evt.Point.Longitude.ToString() + "," + evt.Point.Latitude.ToString());
      xmlWriter.WriteEndElement(); //close coordinates
      xmlWriter.WriteEndElement(); //close point

      xmlWriter.WriteEndElement(); //close placemark

      return sFriendlyName;
    }

    /// <summary>
    /// Get KML for playback from CoT point of interest message
    /// </summary>
    /// <param name="usedStyles">KML Icon styles</param>
    /// <param name="xmlWriter">XML Writer to write KML to</param>
    /// <param name="de">DE parent</param>
    /// <param name="sitRepMsg">CoT point of interest message</param>
    /// <param name="DSCHash">ICNET hash of CoT point of interest message</param>
    /// <returns>description of CoT point of interest message</returns>
    private static string GetPlaybackKMLForCoTPOI(HashSet<ICNETStyle> usedStyles, XmlWriter xmlWriter, CoTWrapper cotmsg, int DSCHash, EDXLDE de)
    {
      //SAMPLE CoT KML
      //<Placemark>
      //  <name>RECON</name>
      //  <TimeStamp>
      //    <when>2005-08-21T09:01:00Z</when>
      //  </TimeStamp>
      //  <styleUrl>#RECON TEAM</styleUrl>
      //  <Point>
      //    <coordinates>55.374000,-4.640000</coordinates>
      //  </Point>
      //</Placemark>

      CotEvent evt = cotmsg.CoTEvent;

      string styleID = string.Empty;
      string sFriendlyName = evt.Type;

      ICNETStyle style = new ICNETStyle();// KMLStyleEngine.GetStyle(cotmsg);

      if (style != null)
      {
        //usedStyles.AddDependencies(style);
        styleID = @"#" + style.KMLStyleName;

        if (!String.IsNullOrWhiteSpace(style.KMLStyleFriendlyName))
        {
          sFriendlyName = style.KMLStyleFriendlyName;
        }
      }
      else
      {
        styleID = string.Empty;// KMLStyleEngine.DefaultStyleId;
      }

      xmlWriter.WriteStartElement("Placemark");

      string localTimeAsString = evt.Time.ToLocalTime().ToString();
      string deIdFixed = de.DistributionID;
      deIdFixed = deIdFixed.Replace("CoTEvent-", ""); //TODO: clean up later

      xmlWriter.WriteElementString("name", deIdFixed);
      xmlWriter.WriteElementString("snippet", "");

      xmlWriter.WriteStartElement("description");

      
      StringBuilder sbDescription = new StringBuilder();

      string sRemarks = GetCoTRemarks(evt);

      if (!string.IsNullOrWhiteSpace(sRemarks))
      {
        sbDescription.Append(sRemarks + "<br><br/>");
      }
      
      Uri uriParams = new Uri(ICNETSOAConstants.ICNETdatalinkToHistoryDEHTML + "?Id=" + de.DistributionID + "&Sender=" + de.SenderID + "&DateTime=" + de.DateTimeSent.ToLocalTime().ToString());
      string sLink = uriParams.AbsoluteUri;

      sbDescription.Append("<a href=\"" + sLink + "\">Details</a><br/>");

      xmlWriter.WriteCData(sbDescription.ToString());
      xmlWriter.WriteEndElement(); //close description

      xmlWriter.WriteStartElement("TimeStamp");
      string zuluTimeAsString = evt.Time.ToString("u");
      zuluTimeAsString = zuluTimeAsString.Replace(' ', 'T');
      xmlWriter.WriteElementString("when", zuluTimeAsString);
      xmlWriter.WriteEndElement(); //close TimeStamp

      xmlWriter.WriteElementString("styleUrl", styleID);

      xmlWriter.WriteStartElement("Point");
      xmlWriter.WriteStartElement("coordinates");
      xmlWriter.WriteString(evt.Point.Longitude.ToString() + "," + evt.Point.Latitude.ToString());
      xmlWriter.WriteEndElement(); //close coordinates
      xmlWriter.WriteEndElement(); //close point

      xmlWriter.WriteEndElement(); //close placemark

      return sFriendlyName;
    }

    /// <summary>
    /// Get remark Text from CoT message
    /// </summary>
    /// <param name="evt">CoT message</param>
    /// <returns>remark Text</returns>
    private static string GetCoTRemarks(CotEvent evt)
    {
      StringBuilder sbRemarks = new StringBuilder();

      //determine if CoT is POI from ICALL
      List<ICotDetailComponent> remarks = evt.Detail.GetElements("remarks");
      if (remarks != null)
      {
        foreach (ICotDetailComponent remark in remarks)
        {
          if (!string.IsNullOrWhiteSpace(remark.XmlNode.InnerText))
          {
            sbRemarks.Append(remark.XmlNode.InnerText + Environment.NewLine);
          }
        }
      }

      return sbRemarks.ToString();
    }

    /// <summary>
    /// Get title from CoT message
    /// </summary>
    /// <param name="evt">CoT message</param>
    /// <returns>title</returns>
    private static string GetTitleForCoT(CotEvent evt)
    {
      string sTitle = "";

      ICotDetailComponent detailsUID = evt.Detail.GetFirstElement("uid");
      if (detailsUID != null && detailsUID.XmlNode != null)
      {
        XmlAttribute fvcotDetailsUID = detailsUID.XmlNode.Attributes["fvcot"];
        XmlAttribute icnetDetailsUID = detailsUID.XmlNode.Attributes["icnet"];

        if (fvcotDetailsUID != null)
        {
          sTitle = fvcotDetailsUID.Value;
        }
        else if (icnetDetailsUID != null)
        {
          sTitle = icnetDetailsUID.Value;
        }
        else
        {
          sTitle = evt.Uid;
        }
      }
      else
      {
        sTitle = evt.Uid;
      }

      return sTitle;
    }

    /// <summary>
    /// Get value from XML attribute
    /// </summary>
    /// <param name="node">XML</param>
    /// <param name="attributeName">attribute name</param>
    /// <returns>attribute value</returns>
    private static string GetValueFromAttribute(XmlNode node, string attributeName)
    {
      XmlAttribute attr = node.Attributes[attributeName];
      string val = "";

      if (attr != null)
      {
        val = attr.Value;
      }

      return val;
    }

    /// <summary>
    /// Get ICNET extension info in the CoT Message
    /// </summary>
    /// <param name="sbDescription">ICNET extension info</param>
    /// <param name="evt">CoT Message</param>
    private static void GetKMLExtensionFromCoT(StringBuilder sbDescription, CotEvent evt)
    {
      string sNumber = "";
      string sBattery = "";
      string sSignal = "";

      ICotDetailComponent details = evt.Detail.GetFirstElement("__icnet");
      if (details != null)
      {
        XmlNode node = details.XmlNode.SelectSingleNode("beacon");
        if (node != null)
        {
          sNumber = GetValueFromAttribute(node, "number");
          sBattery = GetValueFromAttribute(node, "battery");
          sSignal = GetValueFromAttribute(node, "signal");
        }

        string val = "";
        if (sNumber.Length > 0)
        {
          if (sNumber.Length == 10)
          {
            val = sNumber.Substring(0, 3) + "-" + sNumber.Substring(3, 3) + "-" + sNumber.Substring(6);
          }
          else if (sNumber.Length == 11)
          {
            val = sNumber.Substring(0, 1) + "-" + sNumber.Substring(1, 3) + "-" + sNumber.Substring(4, 3) + "-" + sNumber.Substring(7);
          }
          else if (sNumber.Length == 7)
          {
            val = sNumber.Substring(0, 3) + "-" + sNumber.Substring(3);
          }

          sbDescription.Append("number: " + val + "<br/>");
        }

        if (sBattery.Length > 0)
        {
          double dVal;
          bool bCanParse;

          bCanParse = Double.TryParse(sBattery, out dVal);
          if (bCanParse)
          {
            dVal = dVal * 100.0;
            val = dVal.ToString("##.#") + " %";
            sbDescription.Append("battery: " + val + "<br/>");
          }
        }

        if (sSignal.Length > 0)
        {
          val = sSignal + " dBm";
          sbDescription.Append("signal: " + val + "<br/>");
        }
      }
    }

    /// <summary>
    /// Add ICNET extension info in the CoT Message to syndication item
    /// </summary>
    /// <param name="synItem">Syndication item</param>
    /// <param name="evt">CoT Message</param>
    private static void GetGeoRSSExtensionFromCoT(SyndicationItem synItem, CotEvent evt)
    {
      string sNumber = "";
      string sBattery = "";
      string sSignal = "";

      XNamespace ns = ICNETSOAConstants.ICNETNamespace;

      ICotDetailComponent details = evt.Detail.GetFirstElement("__icnet");
      if (details != null)
      {
        XmlNode node = details.XmlNode.SelectSingleNode("beacon");
        if (node != null)
        {
          sNumber = GetValueFromAttribute(node, "number");
          sBattery = GetValueFromAttribute(node, "battery");
          sSignal = GetValueFromAttribute(node, "signal");
        }

        string val = "";
        if (sNumber.Length > 0)
        {
          if (sNumber.Length == 10)
          {
            val = sNumber.Substring(0, 3) + "-" + sNumber.Substring(3, 3) + "-" + sNumber.Substring(6);
          }
          else if (sNumber.Length == 11)
          {
            val = sNumber.Substring(0, 1) + "-" + sNumber.Substring(1, 3) + "-" + sNumber.Substring(4, 3) + "-" + sNumber.Substring(7);
          }
          else if (sNumber.Length == 7)
          {
            val = sNumber.Substring(0, 3) + "-" + sNumber.Substring(3);
          }

            
          XElement element = new XElement(ns + "number");
          element.Value = val;
          synItem.ElementExtensions.Add(element);
        }

        if (sBattery.Length > 0)
        {
          double dVal;
          bool bCanParse;

          bCanParse = Double.TryParse(sBattery, out dVal);
          if (bCanParse)
          {
            dVal = dVal * 100.0;
            val = dVal.ToString("##.#") + " %";
            XElement element = new XElement(ns + "battery");
            element.Value = val;
            synItem.ElementExtensions.Add(element);
          }
        }

        if (sSignal.Length > 0)
        {
          val = sSignal + " dBm";
          XElement element = new XElement(ns + "signal");
          element.Value = val;
          synItem.ElementExtensions.Add(element);
        }
      }
    }

    /// <summary>
    /// Create XML representation the received list
    /// </summary>
    /// <param name="receivedList">Received list</param>
    /// <returns>XML</returns>
    private static List<XElement> CreateReceivedList(List<Received> receivedList)
    {
      List<XElement> mylist = new List<XElement>();
      XElement temp;

      foreach (Received recvd in receivedList)
      {
        temp = new XElement("de");
        temp.Add(new XElement("distributionID", recvd.DEId));
        temp.Add(new XElement("senderID", recvd.DESender));
        temp.Add(new XElement("dateTimeSent", recvd.DEDateTimeSent));
        mylist.Add(temp);
      }

      return mylist;
    }
    #endregion
  }

  /// <summary>
  /// Class to hold KML info
  /// </summary>
  public class KMLInfo
  {
    /// <summary>
    /// KML node type enumeration
    /// </summary>
    public enum KMLTypeEnum
    {
      Location,
      Image,
      SitRep,
      Have,
      Cap,
      Dispatch_Incident,
      Dispatch_Unit,
      Tep,
      POI,
      Other
    }

    /// <summary>
    /// KML node type
    /// </summary>
    public KMLTypeEnum KMLType;

    /// <summary>
    /// string representing KML node
    /// </summary>
    public string KMLString;

    /// <summary>
    /// Distribution ID associated to the KML node
    /// </summary>
    public string DEId;

    /// <summary>
    /// Sender associated to the KML node
    /// </summary>
    public string DESender;

    /// <summary>
    /// Description associated to the KML node
    /// </summary>
    public string Description;
  }
}
